import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { MeetingRoom } from '../meeting-room/entities/meeting-room.entity';
import { UserEntity } from '../user/entities/user.entity';
import { EntityManager, Repository } from 'typeorm';
import { Booking, BookingStatus } from './entities/booking.entity';
import {
  CreateBookingDto,
  ListQueryDto,
  UpdateBookingDto,
} from './dtos/index.dto';
import { EmailService } from 'src/email/email.service';
import { RedisService } from 'src/redis/redis.service';

@Injectable()
export class BookingService {
  @InjectEntityManager()
  private entityManager: EntityManager;

  @InjectRepository(Booking)
  private repository: Repository<Booking>;

  @InjectRepository(UserEntity)
  private userRepository: Repository<UserEntity>;

  @InjectRepository(MeetingRoom)
  private meetingRoomRepository: Repository<MeetingRoom>;

  @Inject()
  private emailService: EmailService;

  @Inject()
  private redisService: RedisService;

  async initData() {
    const user1 = await this.userRepository.findOneBy({
      id: 1,
    });
    const user2 = await this.userRepository.findOneBy({
      id: 2,
    });

    const room1 = await this.meetingRoomRepository.findOneBy({
      id: 1,
    });
    const room2 = await await this.meetingRoomRepository.findOneBy({
      id: 2,
    });

    const booking1 = new Booking();
    booking1.room = room1;
    booking1.user = user1;
    booking1.startTime = new Date();
    booking1.endTime = new Date(Date.now() + 1000 * 60 * 60);

    await this.repository.save(booking1);

    const booking2 = new Booking();
    booking2.room = room2;
    booking2.user = user2;
    booking2.startTime = new Date();
    booking2.endTime = new Date(Date.now() + 1000 * 60 * 60);

    await this.repository.save(booking2);

    const booking3 = new Booking();
    booking3.room = room1;
    booking3.user = user2;
    booking3.startTime = new Date();
    booking3.endTime = new Date(Date.now() + 1000 * 60 * 60);

    await this.repository.save(booking3);

    const booking4 = new Booking();
    booking4.room = room2;
    booking4.user = user1;
    booking4.startTime = new Date();
    booking4.endTime = new Date(Date.now() + 1000 * 60 * 60);

    await this.repository.save(booking4);
  }
  /**
   *
   * @param query
   */
  async list(query: ListQueryDto) {
    const { pageNo, pageSize, userId, roomId, status } = query;
    const entity = this.repository
      .createQueryBuilder('booking')
      .leftJoinAndSelect('booking.room', 'room')
      .leftJoinAndSelect('booking.user', 'user');
    if (userId) {
      entity.andWhere('booking.userId=:userId', { userId });
    }
    if (roomId) {
      entity.andWhere('booking.roomId=:roomId', { roomId });
    }
    if (status) {
      entity.andWhere('booking.status=:status', { status });
    }
    entity.skip(pageSize * (pageNo - 1)).take(pageSize);
    const [list, total] = await entity.getManyAndCount();
    return {
      rows: list,
      total,
    };
  }
  async create(createBookingDto: CreateBookingDto) {
    const { userId, roomId, startTime, endTime, ...reset } = createBookingDto;
    let UserEntity, RoomEntity;
    if (userId) {
      UserEntity = await this.userRepository.findOneBy({ id: +userId });
    }
    if (roomId) {
      RoomEntity = await this.meetingRoomRepository.findOneBy({ id: +roomId });
    }
    const bookings = await this.findOverlapping(startTime, endTime, +roomId);
    console.log(bookings);
    if (bookings.length) {
      throw new BadRequestException('该时间段已被预定');
    }
    await this.repository.save({
      ...reset,
      startTime,
      endTime,
      user: UserEntity,
      room: RoomEntity,
    });
    return {
      msg: '预约成功',
    };
  }
  async findOverlapping(start: Date, end: Date, roomId: number) {
    return this.repository
      .createQueryBuilder('booking')
      .where('booking.room=:roomId', { roomId })
      .andWhere('booking.startTime<:end', { end })
      .andWhere('booking.endTime>:start', { start })
      .getMany();
  }
  async detail(id: number) {
    try {
      const data = await this.repository.findOneOrFail({
        where: { id },
        relations: ['user', 'room'],
      });
      return data;
    } catch (e) {
      throw new BadRequestException('未找到本条预约信息');
    }
  }

  async update(data: UpdateBookingDto) {
    const { id, userId, roomId, startTime, endTime, ...reset } = data;
    let UserEntity, RoomEntity;
    if (userId) {
      UserEntity = await this.userRepository.findOneBy({ id: +userId });
    }
    if (roomId) {
      RoomEntity = await this.meetingRoomRepository.findOneBy({ id: +roomId });
    }
    const bookings = await this.findOverlapping(startTime, endTime, +roomId);
    console.log(bookings);
    if (bookings.length) {
      throw new BadRequestException('该时间段已被预定');
    }
    await this.repository.update(
      { id },
      {
        ...reset,
        startTime,
        endTime,
        user: UserEntity,
        room: RoomEntity,
      },
    );
    return {
      msg: '修改预约成功',
    };
  }
  // 审批通过
  async apply(id: number) {
    await this.repository.update({ id }, { status: BookingStatus.SUCCESS });
    return '审批通过';
  }
  // 驳回
  async reject(id: number) {
    await this.repository.update({ id }, { status: BookingStatus.REJECTED });
    return '已驳回';
  }
  // 取消预约
  async unbind(id: number) {
    await this.repository.update({ id }, { status: BookingStatus.CANCELLED });
    return '已取消';
  }
  // 催办
  async urge(id: number) {
    const flag = await this.redisService.get('urge_' + id);
    if (flag) {
      return '半小时内只能催办一次，请耐心等待';
    }
    let email = await this.redisService.get('admin_email');
    if (!email) {
      const admin = await this.userRepository.findOne({
        select: { email: true },
        where: { isAdmin: true },
      });
      email = admin.email;
      console.log(email);
      this.redisService.set('admin_email', email);
    }

    this.emailService.sendMail({
      to: email,
      subject: '预订申请催办提醒',
      html: `id为${id}的预定申请正在等待审批`,
    });

    this.redisService.set('urge_' + id, 1, 60 * 30);
    return '催办成功';
  }
}
